// 获取rd1的数据，直接输出数据，并产生对应的vsync和href
module gray_get_from_ddr #(
    parameter
        FRAME_ROW              = 16'd480,
        FRAME_LINE             = 16'd640,
        GRAY_GET_FREAME_LIMITE = 16'd3   
)(
    input                               clk              , // 用img时钟 48M
    input                               rst_n            ,
    input                               gray_href        ,
    input                               gray_vsync       ,
    input       [127:0]                 gray_data        ,
    output                              input_fifo_rd_en ,
    output                              gray_vsync_o     ,
    output                              gray_href_o      ,
    output      [ 15:0]                 pas_gray_data_o  ,
    output      [ 15:0]                 cur_gray_data_o  ,
    output reg                          gray_data_valid_o
);

//reg define
reg [15:0] frame_cnt;
reg [15:0] gray_href_cnt;
reg [ 7:0] fifo_en_cnt;
reg [31:0] gray_data_2ch_o;
reg gray_vsync_o_d1;
reg gray_vsync_d1;
reg gray_href_d1;
reg cur_gray_data_flag;
//wire define
wire gray_vsync_pos;
wire gray_vsync_o_pos;
//---------------------------------< main code >----------------------------------
//---------------------------------<  组合逻辑  >----------------------------------
assign gray_vsync_pos = gray_vsync & (~gray_vsync_d1);
assign gray_vsync_o_pos = gray_vsync_o & (~gray_vsync_o_d1);
// 对帧计数，在第二帧后，图像输出数据与ov5640现帧数据保持一帧时差输出
assign input_fifo_rd_en  = ((frame_cnt == GRAY_GET_FREAME_LIMITE) && ((gray_href && (gray_href_cnt == 16'd0)) || ((gray_href_cnt > 16'd1) && (fifo_en_cnt == 8'd7)))) ? 1'd1 : 1'd0;
assign gray_href_o       = (frame_cnt == GRAY_GET_FREAME_LIMITE) ? gray_href_d1 : 1'd0;
assign gray_vsync_o      = (frame_cnt == GRAY_GET_FREAME_LIMITE) ? gray_vsync_d1 : 1'd0;
// pas_gray_data_o 和 cur_gray_data_o
assign cur_gray_data_o = cur_gray_data_flag ? gray_data_2ch_o[31:16] : gray_data_2ch_o[15:0];
assign pas_gray_data_o = (~cur_gray_data_flag) ? gray_data_2ch_o[31:16] : gray_data_2ch_o[15:0];

// gray_data_2ch_o 两帧数据输出
always @(*)begin
    case (fifo_en_cnt)
        8'd0: gray_data_2ch_o = {gray_data[127: 112], gray_data[63:48]};
        8'd1: gray_data_2ch_o = {gray_data[127: 112], gray_data[63:48]};
        8'd2: gray_data_2ch_o = {gray_data[111:  96], gray_data[47:32]};
        8'd3: gray_data_2ch_o = {gray_data[111:  96], gray_data[47:32]};
        8'd4: gray_data_2ch_o = {gray_data[ 95:  80], gray_data[31:16]};
        8'd5: gray_data_2ch_o = {gray_data[ 95:  80], gray_data[31:16]};
        8'd6: gray_data_2ch_o = {gray_data[ 79:  64], gray_data[15: 0]};
        8'd7: gray_data_2ch_o = {gray_data[ 79:  64], gray_data[15: 0]};
        default: gray_data_2ch_o = 32'd0;
    endcase
end
//---------------------------------<  时序逻辑  >----------------------------------
//
// gray_data_valid_o
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
        gray_data_valid_o <= 1'd0;
    else if(gray_href_o)
        gray_data_valid_o <= ~gray_data_valid_o;
    else
        gray_data_valid_o <= 1'd0;
end

// fifo en的控制计数器
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
        fifo_en_cnt <= 8'd0;
    else if(fifo_en_cnt == 8'd7)
        fifo_en_cnt <= 8'd0;
    else if(gray_href_o)
        fifo_en_cnt <= fifo_en_cnt + 8'd1;
    else
        fifo_en_cnt <= 8'd0;
end

// 第一帧以后，frame_cnt稳定在2
always @(posedge clk or negedge rst_n) begin 
    if(~rst_n)
        frame_cnt <= 16'd0;
    else if(frame_cnt == GRAY_GET_FREAME_LIMITE)
        frame_cnt <= frame_cnt;
    else if(gray_vsync_pos)
        frame_cnt <= frame_cnt + 1'd1;
    else ;
end

// href / vsync / img_href_o打拍
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)begin
        gray_vsync_d1 <= 1'd0;
        gray_href_d1 <= 1'd0;
        gray_vsync_o_d1 <= 1'd0;
    end
    else begin
        gray_vsync_d1 <= gray_vsync;
        gray_href_d1 <= gray_href;
        gray_vsync_o_d1 <= gray_vsync_o;
    end
end

// gray_href_cnt
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
        gray_href_cnt <= 16'd0;
    else if(gray_href_cnt == (FRAME_LINE - 16'd1))
        gray_href_cnt <= 16'd0;
    else if((frame_cnt == GRAY_GET_FREAME_LIMITE) && gray_href)
        gray_href_cnt <= gray_href_cnt + 16'd1;
    else ;
end

// gray_href_o_cnt——用于判断现帧的数据
always @(posedge clk or negedge rst_n) begin
    if(~rst_n)
        cur_gray_data_flag <= 1'd0;
    else if(gray_vsync_o_pos)
        cur_gray_data_flag <= ~cur_gray_data_flag;
    else 
        cur_gray_data_flag <= cur_gray_data_flag;
end
endmodule